#include "dialogmain.h"
#include "ui_dialogmain.h"
#include <QAbstractButton>
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QProcess>
#include <QPushButton>
#include <QSettings>
#include <QTimer>
#include <QVBoxLayout>
#include "buttonrelay.h"
#include "serialsettingsdialog.h"
#include "serversettingsdialog.h"
#include "sleepthread.h"

DialogMain::DialogMain(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogMain)
{
    ui->setupUi(this);

    loadConfig(QCoreApplication::applicationDirPath() + "/" + DEF_INI_FILENAME);
    mController.loadController(QCoreApplication::applicationDirPath() + "/" + mIniInfo.mControl, mIniInfo.mCId, mMiscInfo.mIsHeating);
    mController.loadAction(QCoreApplication::applicationDirPath() + "/" + DEF_XML_ACTION);
    mController.loadSunLight(QCoreApplication::applicationDirPath() + "/" + mIniInfo.mSunLight);

    initContextMenu();
    initWidget();
    initSerialPort();
    initTcpSocket();

    connect(this, SIGNAL(signalDayChange(const QDateTime &)), this, SLOT(onDayChanged(const QDateTime &)));
    connect(this, SIGNAL(signalMinuteChange(const QDateTime &)), this, SLOT(onMinuteChanged(const QDateTime &)));
    connect(this, SIGNAL(signalKeepAliveCheck()), this, SLOT(onKeepAlive()));
    mOneSecondTimerId = startTimer(1000);
    mOneSecondTimerCount = 0;

    onLog("+++ Start +++");
}

DialogMain::~DialogMain()
{
    if (mOneSecondTimerId) {
        killTimer(mOneSecondTimerId);
        mOneSecondTimerId = 0;
    }

    if (mSerialPortSendTimerId) {
        killTimer(mSerialPortSendTimerId);
        mSerialPortSendTimerId = 0;
    }

    if (mpSerialPort->isOpen()) {
        mpSerialPort->close();
    }

    saveConfig(QCoreApplication::applicationDirPath() + "/" + DEF_INI_FILENAME);

    onLog("--- End ---");

    delete ui;
}

void DialogMain::timerEvent(QTimerEvent *e)
{
    if (e->timerId() == mOneSecondTimerId) {
        mOneSecondTimerCount++;

        if (false == mIsSerialInit) {
            if (0 == mSerialPortSendPacket.count()) {
                ui->scrollArea->setEnabled(true);
                mIsSerialInit = true;

                if (mSocketServer.mAddress.length() && mSocketServer.mPortNum.length()) {
                    QTimer::singleShot(1000, this, SLOT(onTcpConnect()));
                }

                if (mTemperature.mIsUse) {
                    //mController.temperatureSet(mSerialPortSendPacket, mTemperature.mSetValue);
                    mController.temperatureGet(mSerialPortSendPacket);
                    QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
                }
            }

            return;
        }

        static int _oldMinute = 0, _oldDay = 0;
        QDateTime curDateTime = QDateTime::currentDateTime();
        if (2014 <= curDateTime.date().year()) {
            if (curDateTime.time().minute() != _oldMinute) {
                _oldMinute = curDateTime.time().minute();

                if (curDateTime.date().day() != _oldDay) {
                    _oldDay = curDateTime.date().day();
                    emit signalDayChange(curDateTime);
                }

                //testTimer(curDateTime);
                emit signalMinuteChange(curDateTime);
            }

            if (10 <= mMiscInfo.mKeepAlive) {
                if (1 == ((curDateTime.time().second() % mMiscInfo.mKeepAlive) + 1)) {
                    emit signalKeepAliveCheck();
                }
            }
        }

        if (mTemperature.mIsUse && mTemperature.mInterval) {
            if (0 == (mOneSecondTimerCount % mTemperature.mInterval)) {
                mController.temperatureGet(mSerialPortSendPacket);
                QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
            }
        }
    } else if (e->timerId() == mSerialPortSendTimerId) {
        //qDebug() << "mSerialPortSendTimerId : " << mSerialPortSendTimerId;

        killTimer(mSerialPortSendTimerId);
        mSerialPortSendTimerId = 0;

        QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
    } else {
        int bid = 0;
        if (Relay *pRelay = mController.timerRelay(e->timerId(), &bid)) {
            //qDebug() << "RelayTimeout " << "id: " << pRelay->mId << "idRelay: " << pRelay->mIdRelay << "idRemote: " << pRelay->mIdRemote;

            if (0 <= pRelay->mIdRemote) {
                if ((RELAY_STATUS_AIR <= pRelay->mStatus) && (RELAY_STATUS_HEATING >= pRelay->mStatus)) {
                    mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), pRelay->mStatus);
                }

                mController.packetRelayCurrent(mSerialPortSendPacket, bid, pRelay->mId);
            } else if (0 <= pRelay->mIdRelay) {
                killTimer(pRelay->mTimerId);
                pRelay->mTimerId = 0;

                if (RELAY_STATUS_OFF == pRelay->mStatus) {
                    mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRelay/100), (pRelay->mIdRelay%100), RELAY_STATUS_OFF);
                }
            }

            QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
        }
    }
}

void DialogMain::onParseArgs(const QString& args)
{
    qDebug() << args;
    if (0 == args.compare("quit")) {
        qApp->quit();
    } else {
        emit signalNeedToShow();
    }
}

void DialogMain::onLog(const QString log)
{
    if (mMiscInfo.mIsLog) {
        QDateTime curDateTime = QDateTime::currentDateTime();
        QString msg = curDateTime.toString("[yyyy-MM-dd hh:mm:ss:zzz]") + log;
        const int MAX_FILE_SIZE = 1<<20; // 1[MB]

        int fileNum = 0;
        do {
            QString fileName = QString("%1-%2.log").arg(QCoreApplication::applicationFilePath()).arg(fileNum);
            QFile logFile(fileName);
            if (logFile.open(QFile::WriteOnly | QFile::Append | QFile::Text)) {
                if (MAX_FILE_SIZE < logFile.size()) {
                    fileNum++;
                } else {
                    QTextStream out(&logFile);
                    out << msg << "\n";
                    fileNum = 0;
                }
                logFile.close();
            } else {
                fileNum = 0;
            }
        } while (fileNum);
    }
}

quint32 q_ButtonId= 0;
void DialogMain::onShowContextMenu(const QPoint& pos)
{
    QWidget *widget = childAt(pos);
    QList<QAbstractButton *> listButton = mpButtonGroup->buttons();
    for (int i=0; i<listButton.count(); i++) {
        if (listButton.at(i) == widget) {
            q_ButtonId = mpButtonGroup->id(listButton.at(i));

            QMenu* contextMenu = new QMenu(this);
            contextMenu->addAction("Relay OFF", this, SLOT(onMenuRelayOff()));
            contextMenu->addSeparator();
            contextMenu->addAction("Relay ON", this, SLOT(onMenuRelayOn()));
            contextMenu->exec(mapToGlobal(pos));
            delete contextMenu;
            return;
        }
    }
    q_ButtonId = 0;

    QMenu* contextMenu = new QMenu(this);
    contextMenu->addAction("SerialPort", this, SLOT(onMenuSerialPort()));
    contextMenu->addAction("SocketServer", this, SLOT(onMenuSocketServer()));
    contextMenu->addSeparator();
    contextMenu->addAction("LocalReboot", this, SLOT(onMenuLocalReboot()));
    contextMenu->addAction("ServerReboot", this, SLOT(onMenuServerReboot()));
    contextMenu->addSeparator();
    contextMenu->addAction("Exit", this, SLOT(onMenuExit()));
    contextMenu->exec(mapToGlobal(pos));
    delete contextMenu;
}

void DialogMain::onMenuSerialPort()
{
    SerialSettingsDialog dlg(mSerialPort.mName, &mSerialPort.mPortSettings, this);
    if (QDialog::Accepted == dlg.exec()) {
        mSerialPort.mName = dlg.name();

        saveConfig(QCoreApplication::applicationDirPath() + "/" + DEF_INI_FILENAME);

        QTimer::singleShot(1, this, SLOT(onSerialPortOpen()));
    }
}

void DialogMain::onMenuSocketServer()
{
    QString userId("test"), password("test");
    ServerSettingsDialog dlg(mSocketServer.mAddress, mSocketServer.mPortNum, userId, password, this);
    if (QDialog::Accepted == dlg.exec()) {
        mSocketServer.mAddress = dlg.address();
        mSocketServer.mPortNum = dlg.portNum();

        saveConfig(QCoreApplication::applicationDirPath() + "/" + DEF_INI_FILENAME);

        if (mSocketServer.mAddress.length() && mSocketServer.mPortNum.length()) {
            QTimer::singleShot(10, this, SLOT(onTcpConnect()));
        }
    }
}

void DialogMain::onMenuLocalReboot()
{
    reboot();
}

void DialogMain::onMenuServerReboot()
{
    if (mIsSerialInit && mIsSocketInit) {
        QString packet = mController.packetTcpReboot();
        mpTcpSoceket->write(packet.toUtf8());
    }
}

void DialogMain::onMenuExit()
{
    qApp->quit();
}

void DialogMain::onButtonClicked(int id)
{
    int bid = id / MAX_NUM_RELAY;
    int rid = id % MAX_NUM_RELAY;
    Relay *pRelay = mController.relay(bid, rid);
    if (NULL == pRelay) {
        return;
    }

    qDebug() << "onButtonClicked: bid: " << bid << "rid: " << rid;

    switch (pRelay->mStatus) {
    case RELAY_STATUS_OFF:
        mController.packetRelaySet(mSerialPortSendPacket, bid, rid, RELAY_STATUS_ON);
        break;
    case RELAY_STATUS_ON:
        if (0 <= pRelay->mIdRemote) {
            Relay *pRemote = mController.relay((pRelay->mIdRemote/100), (pRelay->mIdRemote%100));
            if (mMiscInfo.mIsHeating && (REMOTE_VENDOR_LG == pRemote->mRemoteVendor)) {
                // Remote Heating
                mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), RELAY_STATUS_HEATING);
            } else {
                // Remote On -> Remote Air
                mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), RELAY_STATUS_ON);
                //mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), status);
            }
        } else {
            mController.packetRelaySet(mSerialPortSendPacket, bid, rid, RELAY_STATUS_OFF);
        }
        break;
    case RELAY_STATUS_AIR:
        if (0 <= pRelay->mIdRemote) {
            mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), RELAY_STATUS_OFF);
        }
        break;
    case RELAY_STATUS_COOLING:
    case RELAY_STATUS_HEATING:
        if (0 <= pRelay->mIdRemote) {
            mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), RELAY_STATUS_AIR);
        }
        break;
    case RELAY_STATUS_PENDING:
        break;
    case RELAY_STATUS_UNKNOWN:
        if (pRelay->mNotUsed) {
            mController.packetRelaySet(mSerialPortSendPacket, bid, rid, RELAY_STATUS_NOTUSED);
        } else {
            mController.packetRelayGet(mSerialPortSendPacket, bid, rid);
        }
        break;
    case RELAY_STATUS_NOTUSED:
        break;
    }

    QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
}

void DialogMain::onPushDelay(int bid, int rid)
{
    qDebug() << "onPushDelay : " << bid << rid;
    mController.packetRelaySet(mSerialPortSendPacket, bid, rid, RELAY_STATUS_OFF);
}

void DialogMain::onSerialPortOpen()
{
    ui->scrollArea->setEnabled(false);
    mIsSerialInit = false;

    onSerialPortClose();

    mpSerialPort->setPortName(mSerialPort.mName);
    mpSerialPort->setQueryMode(QextSerialPort::EventDriven);
    mpSerialPort->setBaudRate(mSerialPort.mPortSettings.BaudRate);
    mpSerialPort->setDataBits(mSerialPort.mPortSettings.DataBits);
    mpSerialPort->setParity(mSerialPort.mPortSettings.Parity);
    mpSerialPort->setStopBits(mSerialPort.mPortSettings.StopBits);
    mpSerialPort->setFlowControl(mSerialPort.mPortSettings.FlowControl);
    mpSerialPort->setTimeout(mSerialPort.mPortSettings.Timeout_Millisec);

    if (mpSerialPort->open(QIODevice::ReadWrite)) {
        onLog(QString("+ SerialPort Open : %1").arg(mSerialPort.mName));
        mController.packetBoardInit(mSerialPortSendPacket);
        QTimer::singleShot(100, this, SLOT(onSerialPortSend()));
    } else {
        onLog("!!! SerialPort Open Error !!!");
        QMessageBox msgBox;
        msgBox.setText("!!! SerialPort Open Error !!!");
        msgBox.exec();
    }
}

void DialogMain::onSerialPortClose()
{
    if (mSerialPortSendTimerId) {
        killTimer(mSerialPortSendTimerId);
        mSerialPortSendTimerId = 0;
    }
    if (mSerialPortSendPacket.count()) {
        mSerialPortSendPacket.clear();
    }
    mSerialPortRecvBuf.clear();
    if (mpSerialPort->isOpen()) {
        mpSerialPort->close();
        onLog(QString("- SerialPort close : %1").arg(mSerialPort.mName));
    }
}

void DialogMain::onSerialPortSend()
{
    if (mSerialPortSendPacket.count() && (0 == mSerialPortSendTimerId)) {
        mSerialPortSendPacket[0].sendCount++;
        if (1 < mSerialPortSendPacket[0].sendCount) {
            // pending or unknown
            PacketData pd = mSerialPortSendPacket.at(0);
            int cmd = pd.dataBuf[2];
            int bid = pd.dataBuf[3];
            int rid = pd.dataBuf[4];
            if ((PACKET_CMD_SET == cmd) || (PACKET_CMD_GET == cmd)) {
                int status = (mSerialPort.mRetryCount < pd.sendCount) ? RELAY_STATUS_UNKNOWN : RELAY_STATUS_PENDING;

                mController.setRelayStatus(bid, rid, status, this);
                if (ButtonRelay *button = (ButtonRelay *)mpButtonGroup->button(bid*MAX_NUM_RELAY + rid)) {
                    button->setStatus(status);
                }

                bool isRelayBd = (BOARD_TYPE_REMOTE != mController.boardType(bid));
                if (mIsSerialInit && mIsSocketInit && isRelayBd) {
                    QString packet = mController.packetTcpUpdate(bid, rid);
                    mpTcpSoceket->write(packet.toUtf8());
                    onLog(QString("TcpSoceket send : %1").arg(packet));
                }
            }

            if (mSerialPort.mRetryCount < pd.sendCount) {
                onLog(QString("!!! SerialPort sendCount(%1) !!!").arg(pd.sendCount));
                mSerialPortSendPacket.removeFirst();

                if (BOARD_TYPE_REMOTE == mController.boardType(bid)) {
                    if (Relay *pRelay = mController.relay(bid, rid)) {
                        mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRelay/100), (pRelay->mIdRelay%100), RELAY_STATUS_OFF);
                    }
                }

                QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
                return;
            }
        }

        mSerialPortSendPacket[0].sendTime = QTime::currentTime();
        mpSerialPort->write(mSerialPortSendPacket[0].dataBuf);
        if (mSerialPort.mRetryTimeout) {
            mSerialPortSendTimerId = startTimer(mSerialPort.mRetryTimeout);
        }

        QString pdPacket(mSerialPortSendPacket[0].dataBuf.toHex());
        onLog(QString("SerialPort send(%1) : %2").arg(mSerialPortSendPacket[0].sendCount).arg(pdPacket));
    }
}

void DialogMain::onSerialPortRead()
{
    if (mpSerialPort->bytesAvailable()) {
        mSerialPortRecvBuf += mpSerialPort->readAll();

        while (PACKET_MIN_LEN <= mSerialPortRecvBuf.count()) {
            // 7E LEN CMD BID ... CS 7E
            // <STX>01DRS,OK<CR><LF>, <STX>01DWS,OK<CR><LF>
            while ((PACKET_STARTEND != mSerialPortRecvBuf.at(0)) && (0x02 != mSerialPortRecvBuf.at(0))) {
                mSerialPortRecvBuf.remove(0, 1);
                if (PACKET_MIN_LEN > mSerialPortRecvBuf.count()) {
                    return;
                }
            }

            if (0x02 == mSerialPortRecvBuf.at(0)) {
                if (temperatureParsing()) {
                    continue;
                } else {
                    return;
                }
            }

            int nLen = mSerialPortRecvBuf.at(1);
            if (32 <= nLen) {
                mSerialPortRecvBuf.remove(0, 2);
                continue;
            } else if (mSerialPortRecvBuf.count() < nLen) {
                return;
            }

            if (PACKET_STARTEND != mSerialPortRecvBuf.at(nLen - 1)) {
                QString pd(mSerialPortRecvBuf.left(nLen).toHex());
                int a = mSerialPortRecvBuf.at(1);
                QString msg = QString("!!! SerialPort nLen(%1 != %2), %3 %4!!!").arg(nLen).arg(a).arg(pd).arg(mSerialPortRecvBuf.count());
                qDebug() << msg;
                onLog(msg);

                mSerialPortRecvBuf.remove(0, 2);
                continue;
            }

            if (mSerialPortSendTimerId) {
                killTimer(mSerialPortSendTimerId);
                mSerialPortSendTimerId = 0;
            }

            char bCheckSum = 0;
            for (int i=1; i<nLen-2; i++) {
                bCheckSum += mSerialPortRecvBuf.at(i);
            }
            if (mSerialPortRecvBuf.at(nLen-2) == bCheckSum) {
                int nCmd = mSerialPortRecvBuf.at(2);
                {
                    QString pd(mSerialPortRecvBuf.left(nLen).toHex());
                    if (mSerialPortSendPacket.count()) {
                        onLog(QString("SerialPort recv(%1) : %2").arg(mSerialPortSendPacket[0].sendCount).arg(pd));
                    } else {
                        onLog(QString("!!! SerialPort recv : %1 !!!").arg(pd));
                    }
                }
                switch (nCmd) {
                case PACKET_CMD_BDINIT:
                case PACKET_CMD_REMOTEINIT:
                    if (mSerialPortSendPacket.count() && (mSerialPortSendPacket[0].dataBuf.at(2) == nCmd)) {
                        mSerialPortSendPacket.removeFirst();

                        int bid = mSerialPortRecvBuf.at(3);
                        if (PACKET_CMD_BDINIT == nCmd) {
                            qDebug() << "CMD_BDINIT: bid:" << bid;
                            onLog(QString("CMD_BDINIT bid:%1").arg(bid));
                        } else {
                            qDebug() << "CMD_REMOTEINIT: bid:" << bid;
                            onLog(QString("CMD_REMOTEINIT bid:%1").arg(bid));
                        }
                    }
                    break;
                case PACKET_CMD_SET:
                case PACKET_CMD_GET:
                    if (mSerialPortSendPacket.count() && (mSerialPortSendPacket[0].dataBuf.at(2) == nCmd)) {
                        int boardSync = mSerialPortSendPacket[0].boardSync;
                        int timerAction = mSerialPortSendPacket[0].timerAction;
                        mSerialPortSendPacket.removeFirst();

                        int bid = mSerialPortRecvBuf.at(3);
                        int rid = mSerialPortRecvBuf.at(4);
                        int status = mSerialPortRecvBuf.at(5);
                        bool isRelayBd = (BOARD_TYPE_REMOTE != mController.boardType(bid));

                        if (PACKET_CMD_SET == nCmd) {
                            qDebug() << "CMD_SET: bid:" << bid << ", rid:" << rid << ", status:" << status;
                            onLog(QString("CMD_SET bid:%1 rid:%2 status:%3").arg(bid).arg(rid).arg(status));

                            mController.setRelayStatus(bid, rid, status, this);
                            if (false == isRelayBd) {
                                // relay pending...
                                Relay *pRelay = mController.relay(bid, rid);
                                int bid2 = pRelay->mIdRelay / 100;
                                int rid2 = pRelay->mIdRelay % 100;
                                if (ButtonRelay *button = (ButtonRelay *)mpButtonGroup->button(bid2*MAX_NUM_RELAY + rid2)) {
                                    if (button->status() != RELAY_STATUS_PENDING) {
                                        button->setStatus(RELAY_STATUS_PENDING);

                                        if (mIsSerialInit && mIsSocketInit) {
                                            // $update:[cid,bid,rid,status,],$
                                            QString packet("$update:");
                                            packet += QString("[%1,%2,%3,%4,],").arg(mController.mId).arg(bid2).arg(rid2).arg(RELAY_STATUS_PENDING);
                                            packet += "$";
                                            mpTcpSoceket->write(packet.toUtf8());
                                            onLog(QString("TcpSoceket send : %1").arg(packet));
                                        }
                                    }
                                }
                                // relay status reset
                                mController.setRelayStatus(bid2, rid2, RELAY_STATUS_ON, this);

                                if (RELAY_STATUS_ON == status) {
                                    SleepThread::msleep(500);
                                    // Remote On -> Remote Cooling/Heating
                                    mController.packetRelaySet(mSerialPortSendPacket, bid, rid, mMiscInfo.mIsHeating ? RELAY_STATUS_HEATING : RELAY_STATUS_COOLING);
                                } else if (RELAY_STATUS_OFF == status) {
                                    if (RELAY_STATUS_OFF != timerAction) {
                                        // remote timer reset
                                        mController.setRelayStatus(bid, rid, status, this, 0);
                                    }
                                }
                            } else {
                                mController.sendSms(bid, rid);
                            }
                        } else {
                            Relay *pRelay = mController.relay(bid, rid);
                            qDebug() << "CMD_GET: bid:" << bid << ", rid:" << rid << ", status:" << status << ", boardSync:" << boardSync;
                            onLog(QString("CMD_GET bid:%1 rid:%2 status:%3").arg(bid).arg(rid).arg(status));

                            mController.setRelayStatus(bid, rid, status, isRelayBd ? this : NULL);

                            switch (status) {
                            case RELAY_STATUS_PENDING:
                            case RELAY_STATUS_UNKNOWN:
                            case RELAY_STATUS_NOTUSED:
                                if (0 == pRelay->mNotUsed) {
                                    mController.packetRelaySet(mSerialPortSendPacket, bid, rid, RELAY_STATUS_ON);
                                }
                                break;
                            case RELAY_STATUS_ON:
                                if (boardSync) {
                                    mController.packetBoardSync(mSerialPortSendPacket, bid);
                                }
                                break;
                            case RELAY_STATUS_AIR:
                            case RELAY_STATUS_COOLING:
                            case RELAY_STATUS_HEATING:
                                if (0 <= pRelay->mIdRemote) {
                                    mController.packetRelayCurrent(mSerialPortSendPacket, bid, rid);
                                }
                                break;
                            }
                        }

                        if (ButtonRelay *button = (ButtonRelay *)mpButtonGroup->button(bid*MAX_NUM_RELAY + rid)) {
                            if (button->status() != status) {
                                button->setStatus(status);

                                if (mIsSerialInit && mIsSocketInit) {
                                    QString packet = mController.packetTcpUpdate(bid, rid);
                                    mpTcpSoceket->write(packet.toUtf8());
                                    onLog(QString("TcpSoceket send : %1").arg(packet));
                                }
                            }
                        }
                    }
                    break;
                case PACKET_CMD_CURRENT:
                    if (mSerialPortSendPacket.count() && (mSerialPortSendPacket[0].dataBuf.at(2) == nCmd)) {
                        mSerialPortSendPacket.removeFirst();

                        int bid = mSerialPortRecvBuf.at(3);
                        int rid = mSerialPortRecvBuf.at(4);
                        int current = (mSerialPortRecvBuf.at(5) << 8) | mSerialPortRecvBuf.at(6);

                        Relay *pRelay = mController.relay(bid, rid);
                        pRelay->mCurrent = current;
                        int status = mController.currentStatus(pRelay);
                        //qDebug() << "CMD_CURRENT: bid:" << bid << ", rid:" << rid << ", current:" << current << ", status:" << status;
                        onLog(QString("CMD_CURRENT bid:%1 rid:%2 current:%3 status:%4").arg(bid).arg(rid).arg(current).arg(status));

                        if (ButtonRelay *button = (ButtonRelay *)mpButtonGroup->button(bid*MAX_NUM_RELAY + rid)) {
                            if (button->status() != status) {
                                button->setStatus(status);

                                if (mIsSerialInit && mIsSocketInit) {
                                    // $update:[cid,bid,rid,status,],$
                                    QString packet("$update:");
                                    packet += QString("[%1,%2,%3,%4,],").arg(mController.mId).arg(bid).arg(rid).arg(status);
                                    packet += "$";
                                    mpTcpSoceket->write(packet.toUtf8());
                                    onLog(QString("TcpSoceket send : %1").arg(packet));
                                }
                            }
                            button->setCurrent(current);
                        }
                    }
                    break;

                case PACKET_CMD_NOTIFY:
                    if (mTemperature.mIsUse) {
                        int bid = mSerialPortRecvBuf.at(3);
                        int rid = mSerialPortRecvBuf.at(4);
                        int status = mSerialPortRecvBuf.at(5);

                        qDebug() << "CMD_NOTIFY: bid:" << bid << ", rid:" << rid << ", status:" << status;
                        if (0x10 <= rid) {
                            mController.sendSms2(bid, rid, status);
                            mpSerialPort->write(mSerialPortRecvBuf.left(nLen));

                            mController.packetRelayGet(mSerialPortSendPacket, bid, rid-0x10);
                        }
                    }
                    break;

                case PACKET_CMD_NACK:
                    if (mSerialPortSendPacket.count()) {
                        mSerialPortSendPacket[0].sendCount--;

                        QString pd(mSerialPortRecvBuf.left(nLen).toHex());
                        QString msg = QString("!!! SerialPort PACKET_CMD_NACK %1 !!!").arg(pd);
                        qDebug() << msg;
                        onLog(msg);
                    }
                    break;
                default:
                    do {
                        QString pd(mSerialPortRecvBuf.left(nLen).toHex());
                        QString msg = QString("!!! SerialPort PACKET_CMD_UNKNOWN %1 !!!").arg(pd);
                        qDebug() << msg;
                        onLog(msg);
                    } while (false);
                    break;
                }
            } else {
                QString pd(mSerialPortRecvBuf.left(nLen).toHex());
                int a = mSerialPortRecvBuf.at(nLen-2);
                int b = bCheckSum;
                QString msg = QString("!!! SerialPort bCheckSum(%1 != %2), %3 !!!").arg(a).arg(b).arg(pd);
                qDebug() << msg;
                onLog(msg);
            }

            mSerialPortRecvBuf.remove(0, nLen);
        }

        QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
    }
}

void DialogMain::onSerialPortAdded(QextPortInfo portInfo)
{
    qDebug() << "onSerialPortAdded : " << portInfo.portName;
    if (0 == portInfo.portName.compare(mSerialPort.mName)) {
        // open
    }
}

void DialogMain::onSerialPortRemoved(QextPortInfo portInfo)
{
    qDebug() << "onSerialPortRemoved : " << portInfo.portName;
    if (0 == portInfo.portName.compare(mSerialPort.mName)) {
        // close
    }
}

void DialogMain::onTcpConnect()
{
    mIsSocketInit = false;

    if (mpTcpSoceket->isOpen()) {
        mpTcpSoceket->abort();
    }

    mpTcpSoceket->connectToHost(mSocketServer.mAddress, mSocketServer.mPortNum.toInt());
}

void DialogMain::onTcpConnected()
{
    qDebug() << "onTcpConnected() : " << mpTcpSoceket->state();
    onLog(QString("+ TcpSocket Connected : %1").arg(mpTcpSoceket->state()));
    if (QAbstractSocket::ConnectedState == mpTcpSoceket->state()) {
        mIsSocketInit = true;

        // $getfile:filename,$
        QString packet = "$getfile:";
        packet += QString("%1,").arg(DEF_XML_ACTION);
        packet += "$";
        qDebug() << packet;

        mpTcpSoceket->write(packet.toUtf8());
        onLog(QString("TcpSoceket send : %1").arg(packet));
    }
}

void DialogMain::onTcpRead()
{
    QByteArray byteArry;
    while (mpTcpSoceket->bytesAvailable()) {
        byteArry += mpTcpSoceket->readAll();
    }

    QString packet = QString::fromUtf8(byteArry);
    qDebug() << packet;
    onLog(QString("TcpSoceket recv : %1").arg(packet));

    int firstIdx = packet.indexOf('$');
    int lastIdx = packet.lastIndexOf('$');
    if ((-1 < firstIdx) && (-1 < lastIdx)) {
        int findIdx, curIdx = firstIdx + 1;
        QString cmd;

        findIdx = packet.indexOf(':', curIdx);
        cmd = packet.mid(curIdx, (findIdx-curIdx));
        curIdx = findIdx + 1;

        if (!cmd.compare("set")) {
            // $set:[cid,bid,rid,status,],$
            // $update:[cid,bid,rid,status,],[...],$

            firstIdx = packet.indexOf('[', curIdx);
            lastIdx = packet.indexOf(']', curIdx);
            while ((-1 < firstIdx) && (-1 < lastIdx)) {
                curIdx = firstIdx + 1;

                int cid, bid, rid, status;

                findIdx = packet.indexOf(',', curIdx);
                cid = packet.mid(curIdx, (findIdx-curIdx)).toInt();
                curIdx = findIdx + 1;
                qDebug() << "cid:" << cid;

                findIdx = packet.indexOf(',', curIdx);
                bid = packet.mid(curIdx, (findIdx-curIdx)).toInt();
                curIdx = findIdx + 1;
                qDebug() << "bid:" << bid;

                findIdx = packet.indexOf(',', curIdx);
                rid = packet.mid(curIdx, (findIdx-curIdx)).toInt();
                curIdx = findIdx + 1;
                qDebug() << "rid:" << rid;

                findIdx = packet.indexOf(',', curIdx);
                status = packet.mid(curIdx, (findIdx-curIdx)).toInt();
                curIdx = findIdx + 1;
                qDebug() << "status:" << status;

                setStatus(cid, bid, rid, status);
                firstIdx = packet.indexOf('[', curIdx);
                lastIdx = packet.indexOf(']', curIdx);
            }
        } else if (!cmd.compare("sync")) {
            sync();
        } else if (!cmd.compare("reboot")) {
            reboot();
        } else if (!cmd.compare("sendfile")) {
            // $sendfile:filename,filesize,filedata,$
            QString filename, filesize, filedata;

            findIdx = packet.indexOf(',', curIdx);
            filename = packet.mid(curIdx, (findIdx-curIdx));
            curIdx = findIdx + 1;
            qDebug() << "filename:" << filename;

            findIdx = packet.indexOf(',', curIdx);
            filesize = packet.mid(curIdx, (findIdx-curIdx));
            curIdx = findIdx + 1;
            qDebug() << "filesize:" << filesize;

            findIdx = packet.indexOf('$', curIdx);
            filedata = packet.mid(curIdx, (findIdx-curIdx));
            curIdx = findIdx + 1;
            qDebug() << "filedata:" << filedata << filedata.length();


            if (filename == DEF_XML_ACTION) {
                mController.mAction.load(filedata);
                mController.mAction.save(QCoreApplication::applicationDirPath() + "/" + DEF_XML_ACTION);

                QString packet = mController.packetTcpConnect();
                qDebug() << packet;

                mpTcpSoceket->write(packet.toUtf8());
                onLog(QString("TcpSoceket send : %1").arg(packet));
            }
        } else if (!cmd.compare("option")) {
            option(packet, curIdx);
        }
    }
}

void DialogMain::onTcpConnectionClosedByServer()
{
    mIsSocketInit = false;
    qDebug() << "onTcpConnectionClosedByServer()";
    onLog(QString("- TcpSoceket ConnectionClosedByServer"));
}

void DialogMain::onTcpError(QAbstractSocket::SocketError socketError)
{
    switch (socketError) {
    case QAbstractSocket::RemoteHostClosedError:
        break;
    case QAbstractSocket::HostNotFoundError:
        break;
    case QAbstractSocket::ConnectionRefusedError:
        break;
    default:
        break;
    }
    qDebug() << "onTcpError() : " << mpTcpSoceket->errorString();
    onLog(QString("!!! TcpSoceket %1 !!!").arg(mpTcpSoceket->errorString()));

    mpTcpSoceket->abort();

    if (mSocketServer.mAddress.length() && mSocketServer.mPortNum.length()) {
        QTimer::singleShot(5000, this, SLOT(onTcpConnect()));
    }
}

void DialogMain::onDayChanged(const QDateTime &dt)
{
    QString key = dt.date().toString("MM-dd");
    DayInfo di;
    bool isFind = false;

goto_retry:
    if (mController.mSunLight.mMapDays.contains(key)) {
        di = mController.mSunLight.mMapDays.value(key);
        isFind = true;
        qDebug() << "onDayChanged" << di.mDate << di.mTimeSunRise << di.mTimeSunSet;
        onLog(QString("onDayChanged %1 %2 %3").arg(di.mDate.toString("MM-dd")).arg(di.mTimeSunRise.toString("hh:mm")).arg(di.mTimeSunSet.toString("hh:mm")));
    } else {
        if ((2 == dt.date().month()) && (29 == dt.date().day())) {
            key = "02-28";
            goto goto_retry;
        }
    }

    if (isFind) {
        for (int i=0; i<mController.mAction.mTimers.count(); i++) {
            RelayTimer rt = mController.mAction.mTimers[i];

            isFind = false;
            if (TIME_SUNRISE == rt.mStartSunLight) {
                rt.mStartTime = di.mTimeSunRise.toString("hh:mm");
                isFind = true;
            } else if (TIME_SUNSET == rt.mStartSunLight) {
                rt.mStartTime = di.mTimeSunSet.toString("hh:mm");
                isFind = true;
            }

            if (TIME_SUNRISE == rt.mEndSunLight) {
                rt.mEndTime = di.mTimeSunRise.toString("hh:mm");
                isFind = true;
            } else if (TIME_SUNSET == rt.mEndSunLight) {
                rt.mEndTime = di.mTimeSunSet.toString("hh:mm");
                isFind = true;
            }

            if (isFind){
                mController.mAction.mTimers.replace(i, rt);
            }
        }
    }
}

void DialogMain::onMinuteChanged(const QDateTime &dt)
{
    //qDebug() << "onMinuteChanged()" << dt;
    QList<TimerAction> tas;
    int sh, sm, eh, em;

    for (int i=0; i<mController.mAction.mTimers.count(); i++) {
        RelayTimer rt = mController.mAction.mTimers.at(i);
        bool isDayOfWeek = true;
        if (rt.mDayOfWeek) {
            // rt.mDayOfWeek : sun(0), mon(1), ... sat(6)
            // dt.date().dayOfWeek() : mon(1), tue(2), ... sun(7)
            int dow = dt.date().dayOfWeek() % 7;
            if (rt.mDayOfWeek & (1<<dow)) {
                isDayOfWeek = true;
            } else {
                isDayOfWeek = false;
            }
        }
        if (false == isDayOfWeek) {
            continue;
        }

        RelayTimer::parseTime(rt.mStartTime, &sh, &sm);
        RelayTimer::parseTime(rt.mEndTime, &eh, &em);
        if ((dt.time().hour() == sh) && (dt.time().minute() == sm)) {
            TimerAction ta;
            ta.cid = rt.mCId;
            ta.bid = rt.mBId;
            ta.rid = rt.mRId;
            ta.act = rt.mStartAction;
            tas.append(ta);
        } else if ((dt.time().hour() == eh) && (dt.time().minute() == em)) {
            TimerAction ta;
            ta.cid = rt.mCId;
            ta.bid = rt.mBId;
            ta.rid = rt.mRId;
            ta.act = rt.mEndAction;
            tas.append(ta);
        }
    }

    for (int i=0; i<tas.count(); i++) {
        TimerAction ta = tas.at(i);
        if (Relay *pRelay = mController.relay(ta.bid, ta.rid)) {
            switch (ta.act) {
            case RELAY_STATUS_OFF:
                if (0 <= pRelay->mIdRemote) {
                    if (RELAY_STATUS_OFF == pRelay->mStatus) {  // 무시
                    } else {
                        switch (mController.currentStatus(pRelay)) {
                        case RELAY_STATUS_ON:   // 릴레이만 OFF
                            mController.packetRelaySet(mSerialPortSendPacket, ta.bid, ta.rid, ta.act, ta.act);
                            break;
                        case RELAY_STATUS_AIR:
                        case RELAY_STATUS_COOLING:
                        case RELAY_STATUS_HEATING:
                            mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), RELAY_STATUS_OFF, ta.act);
                            break;
                        }
                    }
                } else {
                    mController.packetRelaySet(mSerialPortSendPacket, ta.bid, ta.rid, ta.act, ta.act);
                }
                break;
            case RELAY_STATUS_ON:
                if (0 <= pRelay->mIdRemote) {
                    if (RELAY_STATUS_OFF == pRelay->mStatus) {
                        // off -> on : 릴레이만 ON
                        mController.packetRelaySet(mSerialPortSendPacket, ta.bid, ta.rid, ta.act, ta.act);
                    } else {
                        // on??? -> on : 전류값으로 현상태 파악
                        switch (mController.currentStatus(pRelay)) {
                        case RELAY_STATUS_ON:   // 무시
                            break;
                        case RELAY_STATUS_AIR:
                        case RELAY_STATUS_COOLING:
                        case RELAY_STATUS_HEATING:  // 리모컨만 OFF
                            mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), RELAY_STATUS_OFF, ta.act);
                            break;
                        }
                    }
                } else {
                    mController.packetRelaySet(mSerialPortSendPacket, ta.bid, ta.rid, ta.act, ta.act);
                }
                break;
            case RELAY_STATUS_AIR:
            case RELAY_STATUS_COOLING:
            case RELAY_STATUS_HEATING:
                if (0 <= pRelay->mIdRemote) {
                    if (RELAY_STATUS_OFF == pRelay->mStatus) {
                        // off -> on : 릴레이 ON => 리모컨 제어
                        mController.packetRelaySet(mSerialPortSendPacket, ta.bid, ta.rid, ta.act, ta.act);
                    } else {
                        if (mController.currentStatus(pRelay) != ta.act) {  // 리모컨만 제어
                            mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), ta.act, ta.act);
                        }
                    }
                }
                break;
            }
        }
    }
    if (tas.count()) {
        QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
    }
}

void DialogMain::onKeepAlive()
{
    //qDebug() << "onKeepAlive()";
    for (int b=0; b<mController.mBoards.count(); b++) {
        for (int r=0; r<mController.mBoards[b].mRelays.count(); r++) {
            Relay relay = mController.mBoards[b].mRelays.at(r);
            int bid = mController.mBoards[b].mId;
            int rid = mController.mBoards[b].mRelays[r].mId;
            if (RELAY_STATUS_UNKNOWN == relay.mStatus) {
                if (relay.mNotUsed) {
                    mController.packetRelaySet(mSerialPortSendPacket, bid, rid, RELAY_STATUS_NOTUSED);
                } else {
                    mController.packetRelayGet(mSerialPortSendPacket, bid, rid);
                }
                break;
            } else if (RELAY_STATUS_OFF == relay.mStatus) {
                mController.packetRelayGet(mSerialPortSendPacket, bid, rid, 1);
                break;
            }
        }
    }

    QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
}


void DialogMain::loadConfig(const QString fileName)
{
    QSettings settings(fileName, QSettings::IniFormat);
    settings.setIniCodec("UTF-8");

    settings.beginGroup("IniInfo");
    mIniInfo.mCId = settings.value("cid", 0).toInt();
    mIniInfo.mControl = settings.value("control", DEF_XML_CONTROL).toString();
    mIniInfo.mSunLight = settings.value("sunLight", DEF_INI_SUNLIGHT).toString();
    settings.endGroup();

    settings.beginGroup("SerialPort");
#ifdef Q_OS_WIN32
    mSerialPort.mName = settings.value("name", "COM3").toString();
#else
    mSerialPort.mName = settings.value("name", "ttyO4").toString();
#endif
    mSerialPort.mPortSettings.BaudRate = (BaudRateType)settings.value("baudRate", 9600).toInt();
    mSerialPort.mPortSettings.DataBits = (DataBitsType)settings.value("dataBits", 8).toInt();
    mSerialPort.mPortSettings.Parity = (ParityType)settings.value("parity", 0).toInt();
    mSerialPort.mPortSettings.StopBits = (StopBitsType)settings.value("stopBits", 0).toInt();
    mSerialPort.mPortSettings.FlowControl = (FlowType)settings.value("flowControl", 0).toInt();
    mSerialPort.mPortSettings.Timeout_Millisec = settings.value("timeout", 10).toInt();
    mSerialPort.mRetryCount = settings.value("retryCount", 3).toInt();
    mSerialPort.mRetryTimeout = settings.value("retryTimeout", 50).toInt();
    settings.endGroup();

    settings.beginGroup("SocketServer");
    mSocketServer.mAddress = settings.value("address", "localhost").toString();
    mSocketServer.mPortNum = settings.value("portNum", "58060").toString();
    settings.endGroup();

    settings.beginGroup("MiscInfo");
    mMiscInfo.mIsLog = settings.value("isLog", false).toBool();
    mMiscInfo.mKeepAlive = settings.value("keepAlive", 0).toInt();
    mMiscInfo.mIsHeating = settings.value("isHeating", false).toBool();
    settings.endGroup();

    settings.beginGroup("Temperature");
    mTemperature.mIsUse = settings.value("isUse", false).toBool();
    mTemperature.mInterval = settings.value("interval", 10).toInt();
    mTemperature.mSetValue = settings.value("setValue", 0).toInt();
    settings.endGroup();
}

void DialogMain::saveConfig(const QString fileName)
{
    QFile::remove(fileName);
    QSettings settings(fileName, QSettings::IniFormat);
    settings.setIniCodec("UTF-8");

    settings.beginGroup("IniInfo");
    settings.setValue("cid", mIniInfo.mCId);
    settings.setValue("control", mIniInfo.mControl);
    settings.setValue("sunLight", mIniInfo.mSunLight);
    settings.endGroup();

    settings.beginGroup("SerialPort");
    settings.setValue("name", mSerialPort.mName);
    settings.setValue("baudRate", mSerialPort.mPortSettings.BaudRate);
    settings.setValue("dataBits", mSerialPort.mPortSettings.DataBits);
    settings.setValue("parity", mSerialPort.mPortSettings.Parity);
    settings.setValue("stopBits", mSerialPort.mPortSettings.StopBits);
    settings.setValue("flowControl", mSerialPort.mPortSettings.FlowControl);
    settings.setValue("timeout", (int)mSerialPort.mPortSettings.Timeout_Millisec);
    settings.setValue("retryCount", mSerialPort.mRetryCount);
    settings.setValue("retryTimeout", mSerialPort.mRetryTimeout);
    settings.endGroup();

    settings.beginGroup("SocketServer");
    settings.setValue("address", mSocketServer.mAddress);
    settings.setValue("portNum", mSocketServer.mPortNum);
    settings.endGroup();

    settings.beginGroup("MiscInfo");
    settings.setValue("isLog", mMiscInfo.mIsLog);
    settings.setValue("keepAlive", mMiscInfo.mKeepAlive);
    settings.setValue("isHeating", mMiscInfo.mIsHeating);
    settings.endGroup();

    settings.beginGroup("Temperature");
    settings.setValue("isUse", mTemperature.mIsUse);
    settings.setValue("interval", mTemperature.mInterval);
    settings.setValue("setValue", mTemperature.mSetValue);
    settings.endGroup();
}

void DialogMain::initContextMenu()
{
    setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
            this, SLOT(onShowContextMenu(const QPoint&)));
}

void DialogMain::initWidget()
{
    mpButtonGroup = new QButtonGroup;
    connect(mpButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(onButtonClicked(int)));

    if (ui->scrollArea->takeWidget()) {
        delete ui->scrollArea->takeWidget();
    }

    QWidget *client = new QWidget(this);
    QGridLayout *layout = new QGridLayout(client);
    for (int b=0; b<mController.mBoards.count(); b++) {
        if (BOARD_TYPE_REMOTE == mController.mBoards[b].mType) {
            continue;
        }

        layout->addWidget(new QLabel(mController.mBoards[b].mName), b, 0, Qt::AlignCenter);
        for (int r=0; r<mController.mBoards[b].mRelays.count(); r++) {
            if (0x10 <= mController.mBoards[b].mRelays[r].mId) {
                continue;
            }
            ButtonRelay *button = new ButtonRelay(mController.mBoards[b].mRelays[r].mName,
                                                  mController.mBoards[b].mId,
                                                  mController.mBoards[b].mRelays[r].mId,
                                                  mController.mBoards[b].mRelays[r].mStatus,
                                                  (0 <= mController.mBoards[b].mRelays[r].mIdRemote) ? true : false);
            layout->addWidget(button, b, r+1, Qt::AlignCenter);

            mpButtonGroup->addButton(button, (mController.mBoards[b].mId*MAX_NUM_RELAY + mController.mBoards[b].mRelays[r].mId));
        }
    }
    client->setLayout(layout);
    ui->scrollArea->setWidget(client);
}

void DialogMain::initSerialPort()
{
    mpSerialPort = new QextSerialPort(mSerialPort.mName);
    connect(mpSerialPort, SIGNAL(readyRead()), SLOT(onSerialPortRead()));

    mpSerialEnumerator = new QextSerialEnumerator(this);
    mpSerialEnumerator->setUpNotifications();
    connect(mpSerialEnumerator, SIGNAL(deviceDiscovered(QextPortInfo)), SLOT(onSerialPortAdded(QextPortInfo)));
    connect(mpSerialEnumerator, SIGNAL(deviceRemoved(QextPortInfo)), SLOT(onSerialPortRemoved(QextPortInfo)));

    QTimer::singleShot(1, this, SLOT(onSerialPortOpen()));
}

void DialogMain::initTcpSocket()
{
    mpTcpSoceket = new QTcpSocket(this);
    connect(mpTcpSoceket, SIGNAL(connected()), this, SLOT(onTcpConnected()));
    connect(mpTcpSoceket, SIGNAL(readyRead()), this, SLOT(onTcpRead()));
    connect(mpTcpSoceket, SIGNAL(disconnected()), this, SLOT(onTcpConnectionClosedByServer()));
    connect(mpTcpSoceket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onTcpError(QAbstractSocket::SocketError)));

    /*if (mSocketServer.mAddress.length() && mSocketServer.mPortNum.length()) {
        QTimer::singleShot(1000, this, SLOT(onTcpConnect()));
    }*/
}

void DialogMain::setStatus(int cid, int bid, int rid, int status)
{
    if (mController.mId != cid) {
        return;
    }

    Relay *pRelay = mController.relay(bid, rid);
    if (NULL == pRelay) {
        return;
    }

    switch (status) {
    case RELAY_STATUS_OFF:
        if (0 <= pRelay->mIdRemote) {
            // remote -> delay -> relay
            mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), status);
        } else {
            mController.packetRelaySet(mSerialPortSendPacket, bid, rid, status);
        }
        break;
    case RELAY_STATUS_ON:
        mController.packetRelaySet(mSerialPortSendPacket, bid, rid, status);
        break;
    case RELAY_STATUS_AIR:
        if (0 <= pRelay->mIdRemote) {
            // relay -> delay -> remote
            mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), status);
        }
        break;
    case RELAY_STATUS_COOLING:
    case RELAY_STATUS_HEATING:
        if (0 <= pRelay->mIdRemote) {
            Relay *pRemote = mController.relay((pRelay->mIdRemote/100), (pRelay->mIdRemote%100));
            if (mMiscInfo.mIsHeating && (REMOTE_VENDOR_LG == pRemote->mRemoteVendor)) {
                // Remote Heating
                mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), RELAY_STATUS_HEATING);
            } else {
                // Remote On -> Remote Air
                mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), RELAY_STATUS_ON);
                //mController.packetRelaySet(mSerialPortSendPacket, (pRelay->mIdRemote/100), (pRelay->mIdRemote%100), status);
            }
        }
        break;
    case RELAY_STATUS_PENDING:
    case RELAY_STATUS_UNKNOWN:
        mController.packetRelayGet(mSerialPortSendPacket, bid, rid);
        break;
    case RELAY_STATUS_NOTUSED:
        break;
    }

    QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
}

void DialogMain::sync()
{
    mController.packetBoardSync(mSerialPortSendPacket);
    QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
}

void DialogMain::reboot()
{
#ifdef Q_OS_WIN32
    QString program = (QCoreApplication::applicationDirPath() + "/" + "cubeupdate.exe");
#else
    QString program = (QCoreApplication::applicationDirPath() + "/" + "cubeupdate");
#endif
    QStringList argments;
    argments << "reboot";
    argments << "5";    // delay
    argments << QCoreApplication::applicationFilePath();

    QProcess::startDetached(program, argments);
    QTimer::singleShot(100, this, SLOT(onMenuExit()));
}

void DialogMain::option(QString &packet, int curIdx)
{
    int firstIdx, lastIdx, findIdx;

    // $option:[,],[,],$
    firstIdx = packet.indexOf('[', curIdx);
    lastIdx = packet.indexOf(']', curIdx);
    while ((-1 < firstIdx) && (-1 < lastIdx)) {
        curIdx = firstIdx + 1;

        int idOption, var1;

        findIdx = packet.indexOf(',', curIdx);
        idOption = packet.mid(curIdx, (findIdx-curIdx)).toInt();
        curIdx = findIdx + 1;
        qDebug() << "idOption:" << idOption;

        switch (idOption) {
        case 1: // cooling(0), heating(1)
            findIdx = packet.indexOf(',', curIdx);
            var1 = packet.mid(curIdx, (findIdx-curIdx)).toInt() ? true : false;
            curIdx = findIdx + 1;
            qDebug() << "var1:" << var1;
            if (var1 != mMiscInfo.mIsHeating) {
                mMiscInfo.mIsHeating = var1;
                reboot();
            }
            break;
        case 2: // Temperature setValue(0)
            findIdx = packet.indexOf(',', curIdx);
            var1 = packet.mid(curIdx, (findIdx-curIdx)).toInt();
            curIdx = findIdx + 1;
            qDebug() << "var1:" << var1;
            if (mTemperature.mSetValue != var1) {
                mController.temperatureSet(mSerialPortSendPacket, var1);
                QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
            }
            break;
        }

        firstIdx = packet.indexOf('[', curIdx);
        lastIdx = packet.indexOf(']', curIdx);
    }
}

void DialogMain::testTimer(const QDateTime &dt)
{
    QList<TimerAction> tas;

    for (int b=0; b<mController.mBoards.count(); b++) {
        if (BOARD_TYPE_REMOTE == mController.mBoards[b].mType) {
            continue;
        }

        for (int r=0; r<mController.mBoards[b].mRelays.count(); r++) {
            int bid = mController.mBoards[b].mId;
            int rid = mController.mBoards[b].mRelays[r].mId;

            TimerAction ta;
            ta.cid = mController.mId;
            ta.bid = bid;
            ta.rid = rid;
            if (dt.time().minute() % 2) {
                // off
                ta.act = RELAY_STATUS_OFF;
            } else {
                // on
                ta.act = RELAY_STATUS_ON;
            }

            if (Relay *pRelay = mController.relay(ta.bid, ta.rid)) {
                if (0 > pRelay->mIdRemote) {
                    tas.append(ta);
                }
            }
        }
    }
    for (int i=0; i<tas.count(); i++) {
        TimerAction ta = tas.at(i);
        mController.packetRelaySet(mSerialPortSendPacket, ta.bid, ta.rid, ta.act);
    }
    if (tas.count()) {
        QTimer::singleShot(1, this, SLOT(onSerialPortSend()));
    }
}

bool DialogMain::temperatureParsing()
{
    if (false == mTemperature.mIsUse) {
        mSerialPortRecvBuf.remove(0, 1);
        return true;
    }

    int idxLF = 0;
    for (int i=0; i<mSerialPortRecvBuf.count(); i++) {
        if (0x0A == mSerialPortRecvBuf.at(i)) {
            idxLF = i;
            break;
        }
        if (0x7E <= mSerialPortRecvBuf.at(i)) {
            qDebug() << mSerialPortRecvBuf.toHex();
            mSerialPortRecvBuf.remove(0, i+1);
            return true;
        }
    }
    if (0 == idxLF) {
        return false;
    }

    if (mSerialPortSendTimerId) {
        killTimer(mSerialPortSendTimerId);
        mSerialPortSendTimerId = 0;
    }

    if (mSerialPortSendPacket.count()) {
        mSerialPortSendPacket.removeFirst();

        QString strRecv(mSerialPortRecvBuf.mid(1, (idxLF - 2)));
        qDebug() << strRecv;
        if (strRecv.contains(QString("01DRS"))) {
            bool ok;
            mTemperature.mCurValue = strRecv.mid(9, 4).toShort(&ok, 16);
            mTemperature.mSetValue = strRecv.mid(14, 4).toShort(&ok, 16);
            qDebug() << "Cur:" << mTemperature.mCurValue << ", Set:" << mTemperature.mSetValue;

            if (mIsSerialInit && mIsSocketInit) {
                // $temperature:curvalue,setvalue,$
                QString packet("$temperature:");
                packet += QString("%1,%2,").arg(mTemperature.mCurValue).arg(mTemperature.mSetValue);
                packet += "$";
                mpTcpSoceket->write(packet.toUtf8());
                onLog(QString("TcpSoceket send : %1").arg(packet));
            }
        }
    }

    mSerialPortRecvBuf.remove(0, (idxLF + 1));

    return true;
}
